iT邦幫忙

2025 iThome 鐵人賽

DAY 6
0

前言

歡迎回來!再堅持一下,很快第一週就要結束了! 沒意外的話到明天就會將我們目前所有的進度都整合成一個堪用的產品,你很快就可以至少跟那樣簡陋的頁面道別了!我們昨天已經藉由整合既有的套件讓程式碼編輯器可以在指定題型時出現,同時也確認我們可以取得使用者輸入的程式碼內容,算是已經為了之後的程式碼執行部分打了不錯的基礎。

今天要做的部分算是我認為第一週最重要的內容了,之前幾天的內容絕大多數都在講一些基礎的設置,而其中又有很大一部分的設置是專門針對整個 AI 面試官這個示範專案做的,雖然以一個文章計畫來說這沒有什麼問題,但整個系列文我是希望藉由這個示範專案,讓讀者帶走做 AI 專案的能力,所以許多枝微末節的事項像是 UI 設計我都盡可能快速帶過,不過為了文章的完整性還是必須佔有蠻多的篇幅,對於想跟著文章打造屬於自己專案的讀者(雖然我不確定這樣的人存不存在就是了),我一直有點抱歉。

如果真有這樣的讀者,那我希望今天的文章對你來說有點幫助!目前我們雖然有用 AI 作為回應,但就像昨天提到的,其實目前我們在 Day2 給它的「劇本」只是堪用而已,今天就要來學習 AI 應用的核心技術之一:Prompt Engineering(提示工程)。對目前提供給 AI 的「劇本」進行第一次升級,教會它如何使用輸出我們想要的格式,並認識業界公認的最佳實踐。

今日目標

  • 學習來自 Google, OpenAI, Anthropic 的 Prompt Engineering 核心原則。

  • 認識實用的 Prompt 產生器與資源庫,加速開發流程。

  • 修改後端 API,打造一個結構化的指令,並確保 AI 以繁體中文回覆。

  • 讓 AI 的回饋更精準、更具一致性、更可靠。

Prompt Engineering 實戰手冊

在動手修改程式碼前,讓我們先建立正確的觀念,先定義什麼是Prompt Engineering 。簡單搓就是「如何更好地與 AI 對話,以獲得你想要的結果」的技巧。與其把 AI 當成一個黑盒子許願, 不如把它當成一個能力極強、但需要清晰指令的實習生,在打造一個更聰明的 AI 之前,讓我們先明確一下它的角色。目前我們「一次性提交 -> 得到完整回饋」的模式,更像一個「AI 練習助理」。它的目標是針對單一問題,提供最詳盡、最完整的解析,幫助使用者深入學習,在第三週的時候我們才會進一步拓展它的可能性,讓他更貼近面試官這個角色。

若你有稍微在關注 AI 相關的議題的話,我想你會知道不管在哪個學習平台或是網站都有著大量的影片或文章說明他們認為的有效技巧是什麼,坦白說每個聽起來都很有道理,一時間也許會讓你有些不知所措,在這種時候我傾向把目光投注在幾個比較權威的說法,下方就是來自 Google (Gemini), OpenAI (ChatGPT), Anthropic (Claude) 官方文件公認的幾大關鍵技巧:

技巧 1:角色扮演 (Give the model a persona)

給予 AI 一個明確的角色,可以有效地將它的回應限縮在特定領域。

  • Bad ❌: 評價這個答案。

  • Good ✅: 你是一位資深的前端技術面試官,擁有十年以上經驗,擅長從根本上解釋觀念。請用專業但友善的語氣,評價這個答案。

技巧 2:提供上下文與範例 (Provide context and examples)

提供相關的背景資訊、參考資料或「標準答案」。對我們的專案來說,keyPoints 就是最完美的上下文。

  • Bad ❌: 問題是 Hoisting,答案是「變數提升」,這樣對嗎?

  • Good ✅: 問題是 Hoisting,這是評分標準:[提到 var/let/const 的差異, 提到 TDZ]。考生的答案是「變數提升」。請根據評分標準評價。

技巧 3:使用分隔符,特別是 XML 標籤 (Use delimiters, especially XML tags)

當你的 Prompt 包含不同區塊時,使用清晰的分隔符(特別是 XML 標籤)可以幫助 AI 準確地區分各個部分,提升穩定性。

  • Good ✅:
<instruction>...</instruction>
<evaluation_criteria>...</evaluation_criteria>
<candidate_answer>...</candidate_answer>

技巧 4:給予逐步指令 (Ask for a step-by-step output)

要求 AI 一步一步來,這種「思維鏈 (Chain-of-Thought)」的提示方式,可以顯著提升 AI 在複雜任務上的表現和輸出品質。

  • Good ✅:
請依照以下步驟給我回饋:
1.  **逐點分析**: ...
2.  **給予回饋**: ...

技巧 5:提供輸出範例 (Provide output examples / Few-shot)

這可以說是所有的說法中大家普遍認知的共識了,給予明確的指示要求他在限定範圍內遵守格式回覆可以大幅提升回應的品質,尤其你要求他做一些比較複雜的整理或轉換時,提供輸入輸出的範例通常都會相當有效。

  • Good ✅:
    請完全依照以下 Markdown 格式輸出:
### 綜合評估
**✅ 答對部分**
* [這裡針對答對的點進行說明...]

**🔍 可補充部分**
* [這裡針對可以更好的點進行說明...]

**⭐ 總結**
[這裡給予總結與建議...]

輔助工具:Prompt 產生器與資源庫

手寫 Prompt 雖然靈活,但有時候我們也需要一些靈感或工具來加速這個過程。社群上有許多優秀的工具可以幫助我們建構、管理和發現好的 Prompt,之前 Open AI 和 Gemini甚至有提供 Prompt Generator功能的使用,可惜我最近再回去看他們的 playground 似乎已經沒有這個功能了,這邊就僅提供一些熱門的 Prompt 資源讓你做初步的參考。

工具名稱 類型 說明 連結
Anthropic's Prompt Library 官方資源庫 由 Claude 開發團隊提供的官方 Prompt 範例庫,涵蓋各種情境,是學習如何結構化 Prompt 的絕佳起點。 點擊前往
Awesome ChatGPT Prompts GitHub 資源庫 一個由社群共同維護的 GitHub Repo,收集了大量針對不同角色的 ChatGPT Prompt,非常適合直接複製使用或修改。 點擊前往

Step 1: 升級我們的 API 劇本

好,理論知識與輔助工具都備齊了!現在,讓我們把這些技巧應用到專案中。打開 app/api/gemini/route.ts,我們要用剛學到的技巧來重構我們的 Prompt。

import { GoogleGenAI } from '@google/genai';
import { NextResponse } from 'next/server';
const GEMINI_API_KEY = process.env.GEMINI_API_KEY;

const ai = new GoogleGenAI({ apiKey: GEMINI_API_KEY });

export async function POST(request: Request) {
  try {
    const { question, answer, keyPoints } = await request.json();

    // 設計提示詞,讓 AI 扮演前端面試官
    const prompt = `
      <role>
      You are a world-class senior frontend technical interviewer with over 10 years of experience. Your tone is professional, encouraging, and helpful. You are an expert in explaining complex concepts clearly.
      </role>

      <task>
      Your task is to evaluate a candidate's answer based on the provided "Evaluation Criteria". Follow these steps precisely:
      1.  **Analyze**: Go through each point in the "Evaluation Criteria" one by one and check if the candidate's "Answer" covers it.
      2.  **Feedback**: Provide detailed feedback strictly following the Markdown format in "<example_output>". For points the candidate got right, offer praise and add depth. For points the candidate missed, gently correct them and explain the concept.
      3.  **Summarize**: Conclude with an overall summary and suggest a next step for their learning. Don't be too long with the summary.
      4.  **Language**: All your output MUST be in Traditional Chinese (繁體中文).
      </task>
      
      <example_output>
      ### 綜合評估
      **✅ 答對部分**
      * 你很棒地解釋了 hoisting 的基本概念,提到「變數和函數宣告會被提升到其作用域的頂部」。這點完全正確!
      
      **🔍 可補充部分**
      * 可以更深入說明 **let 和 const** 的 hoisting 行為。雖然它們也會被提升,但因為「暫時性死區 (TDZ)」的存在,在宣告前存取會拋出錯誤,這點是和 var 的關鍵區別。
      </example_output>
      <question>
      ${question}
      </question>

      <candidate_answer>
      ${answer}
      </candidate_answer>

      <evaluation_criteria>
      ${keyPoints.map((point: string) => `- ${point}`).join('\n')}
      </evaluation_criteria>
    `;

    // 使用 Gemini 提供的AI模型去取得回應
    const response = await ai.models.generateContent({
      model: 'gemini-2.5-flash',
      contents: prompt,
    });
    const text = response.text;

    // 回傳回應
    return NextResponse.json({ result: text });
  } catch (error) {
    console.error('Gemini API error:', error);
    return NextResponse.json(
      { error: '無法生成回饋,請稍後再試' },
      { status: 500 }
    );
  }
}

幾個關鍵的改動如下:

  1. 我們將 promptk 的內容轉為以英文為主,只是最後輸出時要求他以中文輸出,這麼做的目的是為了增加模型理解的能力,由於模型都還是眾多資料訓練出來的成果,許多引用都指出英文的資料得利於數量眾多,模型在處理英文的資訊時確實會更為優秀一些。
  2. 將我們題目中的 keyPoints 也作為 prompt的一部分發給 Gemini ,這可以讓他更容易判斷使用者是否真的有正確回答到我們的問題,同時也是作為之後評分系統實踐的指標之一。
  3. 更明確的規範了他的回覆格式以及步驟,讓整個回應更容易掌控。

Step 2: 前端發送更多資訊

後端劇本升級後,前端也需要配合,確保 keyPoints 有被一起送出。
打開 app/page.tsx,修改 handleSubmit 函式:

// ...  
  const handleSubmit = async () => {
    if (!answer) return;
    try {
      setIsLoading(true);

      // 發送請求到我們剛剛在後端app/api/gemini/route.ts建立的API
      const response = await fetch('/api/gemini', {
        method: 'POST',
        body: JSON.stringify({
          question: currentQuestion?.question,
          answer,
          keyPoints: currentQuestion?.keyPoints, // 確認加入這行
        }),
      });
      const data = await response.json();

      setFeedback(data.result);
    } catch (error) {
      console.error('錯誤:', error);
    } finally {
      setIsLoading(false);
    }
  };
//...

Step 3: 測試更聰明的 AI

搞定!儲存所有檔案,回到 http://localhost:3000。找到一題概念題,例如 hoisting,我們用跟第二天一模一樣的題目與回答做個測試。

圖1
圖1 :更新Prompt後測試結果

你會發現相較於之前的版本,回覆的格式變得更穩定且真的有按照我們設定的方式進行回覆,即便是反覆多試幾次你也會發現它相當的穩定(當然,偶爾還是會因為幻覺的關係胡說八道,這點我們會在第四週時去做討論),我們做的事情並不多,但成效卻相當得不錯,蠻有意思的吧!

今日回顧

今天我們為 AI 裝上了「導航系統」,讓它的智慧不再漫無目的地遊走。

✅ 學習了來自多家頂尖公司的 Prompt Engineering 核心技巧
✅ 介紹了實用的 Prompt 資源庫
✅ 釐清了「練習助理」與「擬真面試官」的產品定位
✅ 升級了後端 Prompt,使其更結構化且穩定回覆

明天預告

我們的核心功能提問、作答、回饋的 MVP 基本已經完成了!雖然還有些粗糙,但它已經可以運作了。明天(Day 7),我們要做一件令人興奮的事:打造第一個可分享的 MVP!我們會將目前的成果做個整合並進行部署,讓我們這一週能確實地端出實際的成果!

參考資料

  1. Google AI for Developers: Introduction to prompt design
  2. OpenAI Cookbook: Prompt engineering
  3. Anthropic (Claude) Docs: Introduction to prompting

今日程式碼: https://github.com/windate3411/Itiron-2025-code/tree/day-6


上一篇
打造專業作答區:整合 Monaco Editor
下一篇
整合與部署:將專案整合一週的內容後推上Vercel吧!
系列文
前端工程師的AI應用開發實戰:30天從Prompt到Production - 以打造AI前端面試官為例8
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言